package team.qwer.demo.common.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import team.qwer.demo.common.util.httpservletwrapper.RequestWrapper;
import team.qwer.demo.common.util.httpservletwrapper.ResponseWrapper;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Map;

public class LogFilter implements Filter {

    private static final Logger LOGGER = LoggerFactory.getLogger(LogFilter.class);
    private static final String SEPARATOR = "=";
    private final Level logLevel;

    public LogFilter(Level logLevel) {
        this.logLevel = logLevel;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //just statement
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (logLevel.toInt() > Level.INFO.toInt()) {
            chain.doFilter(request, response);
            return;
        }
        RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) request);
        ResponseWrapper responseWrapper = new ResponseWrapper((HttpServletResponse) response);
        String charset = request.getCharacterEncoding();
        if (charset == null) {
            charset = StandardCharsets.UTF_8.name();
        }
        String input = new String(requestWrapper.getCacheStream().toByteArray(), charset);
        LOGGER.info("request ip:{}", NetworkUtil.getIpAddress(requestWrapper));
        LOGGER.info("request path:{}", requestWrapper.getRequestURI());
        LOGGER.info("request headers:{}", getHeaders(requestWrapper));
        LOGGER.info("request params:{}", getRequestParam(requestWrapper));
        LOGGER.info("request message:\n{}", input);
        chain.doFilter(requestWrapper, responseWrapper);
        response.getOutputStream().write(responseWrapper.getResponseData());
        LOGGER.info("response headers:{}", getResponseHeaders(responseWrapper));
        LOGGER.info("response message:\n{}", getResponseOutput(responseWrapper));
    }

    /**
     * 获取请求头
     *
     * @param request
     * @return
     */
    private String getHeaders(HttpServletRequest request) {
        Enumeration headerElements = request.getHeaderNames();
        StringBuilder headers = new StringBuilder();
        while (headerElements.hasMoreElements()) {
            String headerName = headerElements.nextElement().toString();
            headers.append(headerName).append(SEPARATOR).append(request.getHeader(headerName)).append(";");
        }
        return headers.toString();
    }

    private String getRequestParam(HttpServletRequest request) {
        Map<String, String[]> parameterMap = request.getParameterMap();
        StringBuilder params = new StringBuilder();
        parameterMap.forEach((key, values) -> {
            for (String value : values) {
                params.append(key).append(SEPARATOR).append(value).append(";");
            }
        });
        return params.toString();
    }

    private String getResponseOutput(ResponseWrapper responseWrapper) throws IOException {
        return new String(responseWrapper.getResponseData(), StandardCharsets.UTF_8);
    }

    private String getResponseHeaders(ResponseWrapper responseWrapper) {
        Collection<String> headerElements = responseWrapper.getHeaderNames();
        StringBuilder headers = new StringBuilder();
        for (String headerName : headerElements) {
            headers.append(headerName).append(SEPARATOR).append(responseWrapper.getHeader(headerName)).append(";");
        }
        return headers.toString();
    }

    @Override
    public void destroy() {
        //just statement
    }
}
